/*
 * Copyright 2008-2023 dexian.vip. All rights reserved.
 * Support: http://www.dexian.vip
 * License: http://www.dexian.vip/license
 */

package vip.dexian.common.utils;

import cn.hutool.core.lang.Assert;
import vip.dexian.common.CommonAttributes;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
 * LocalDateTime 工具类
 *
 * @author 挺好的 2023年05月30日 8:15
 */
public final class LocalDateTimeUtils {

    private LocalDateTimeUtils () {
    }

    /**
     * {@link java.util.Date}转{@link java.time.LocalDateTime}，使用默认时区。
     *
     * <p>
     * 1. date 如果为 year ，返回 year-01-01T00:00
     * <p>
     * 2. date 如果为year-month， 返回 year+month-01T00:00
     * <p>
     * 3. date 如果为year-month-day， 返回 year+month-dayT00:00。以此类推
     *
     * @param date
     *         日期{@link java.util.Date}
     *
     * @return date == null, return null。否则返回 {@link java.time.LocalDateTime}
     */
    public static LocalDateTime of (Date date) {
        if (date == null) {
            return null;
        }
        return of(date.toInstant());
    }

    /**
     * 毫秒转{@link java.time.LocalDateTime}，使用默认时区
     *
     * <p>注意：此方法使用默认时区，如果非UTC，会产生时间偏移</p>
     *
     * @param epochMilli
     *         从1970-01-01T00:00:00Z开始计数的毫秒数
     *
     * @return {@link java.time.LocalDateTime}
     */
    public static LocalDateTime of (long epochMilli) {
        return of(Instant.ofEpochMilli(epochMilli));
    }


    /**
     * {@link java.time.Instant}转{@link java.time.LocalDateTime}，使用默认时区
     *
     * @param instant
     *         {@link java.time.Instant}
     *
     * @return {@link java.time.LocalDateTime}
     */
    public static LocalDateTime of (Instant instant) {
        return of(instant, ZoneId.systemDefault());
    }

    /**
     * {@link java.time.Instant}转{@link java.time.LocalDateTime}
     *
     * @param instant
     *         {@link java.time.Instant}
     * @param zoneId
     *         时区
     *
     * @return {@link java.time.LocalDateTime}
     */
    public static LocalDateTime of (Instant instant, ZoneId zoneId) {
        if (null == instant) {
            return null;
        }

        if (ObjectUtils.isEmpty(zoneId)) {
            zoneId = ZoneId.systemDefault();
        }

        return LocalDateTime.ofInstant(instant, zoneId);
    }

    /**
     * 格式化日期，如果pattern is empty， 将使用模式(yyyy-MM-dd HH:mm:ss) 格式化日期。
     *
     * @param pattern
     *         日期模式
     * @param localDateTime
     *         {@link java.time.LocalDateTime}
     *         待格式化的日期。
     *
     * @return 如果localDateTime为null，返回 null
     */
    public static String format (String pattern, LocalDateTime localDateTime) {

        if (localDateTime == null) {
            return null;
        }

        if (StringUtils.isEmpty(pattern)) {
            pattern = CommonAttributes.DatePattern.DATE_TIME_1;
        }

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);

        return formatter.format(localDateTime);
    }

    /**
     * 格式化日期，使用模式(yyyy-MM-dd HH:mm:ss) 格式化日期。
     *
     * @param localDateTime
     *         {@link java.time.LocalDateTime}
     *         待格式化的日期。
     *
     * @return 如果localDateTime为null，返回 null
     */
    public static String format (LocalDateTime localDateTime) {
        return format(CommonAttributes.DatePattern.DATE_TIME_1, localDateTime);
    }

    /**
     * 开始时间是否小于结束时间（开始时间是否在结束时间之前）
     *
     * @param begin
     *         开始时间
     * @param end
     *         结束时间
     *
     * @return begin == null || end == null ，返回true。begin <= end，返回true，否则返回false
     * {@link java.time.LocalDateTime#isBefore(java.time.chrono.ChronoLocalDateTime)}
     */
    public static boolean isBefore (LocalDateTime begin, LocalDateTime end) {
        if (begin == null || end == null) {
            return true;
        }

        return begin.isBefore(end);
    }

    /**
     * 开始时间是否大于结束时间（开始时间是否在结束时间之后）
     *
     * @param begin
     *         开始时间
     * @param end
     *         结束时间
     *
     * @return begin == null || end == null ，返回true。begin > end，返回true，否则返回false
     * {@link java.time.LocalDateTime#isAfter(java.time.chrono.ChronoLocalDateTime)}
     */
    public static boolean isAfter (LocalDateTime begin, LocalDateTime end) {
        if (begin == null || end == null) {
            return true;
        }

        return begin.isAfter(end);
    }

    /**
     * 获取指定时间的开始时间。 date time  00:00，该方法没有返回秒数或者毫秒数
     *
     * @param localDateTime
     *         指定时间的开始时间
     *
     * @return {@link java.time.LocalDateTime}
     *
     * @see java.time.LocalDate
     */
    public static LocalDateTime getMinTime (LocalDateTime localDateTime) {

        Assert.notNull(localDateTime, "local date time is required");
        return localDateTime.toLocalDate().atTime(LocalTime.of(0, 0, 0));
    }

    /**
     * 获取指定时间的结束时间。date time 23:59:59
     *
     * @param localDateTime
     *         指定时间
     *
     * @return {@link java.time.LocalDateTime}
     *
     * @see java.time.LocalDate
     * @see java.time.OffsetTime
     */
    public static LocalDateTime getMaxTime (LocalDateTime localDateTime) {

        Assert.notNull(localDateTime, "local date time is required");


        return localDateTime.toLocalDate().atTime(LocalTime.of(23, 59, 59));
    }

    /**
     * 将localDateTime转换为时间戳
     *
     * @param localDateTime
     *         待转换的时间
     *
     * @return 转换后的毫秒数
     */
    public static long dateToTimestamp (LocalDateTime localDateTime) {
        if (localDateTime == null) {
            throw new IllegalArgumentException(" date time must not null");
        }

        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        return instant.toEpochMilli();
    }

    /**
     * 获取当前时间的毫秒数
     *
     * @return 当前时间的毫秒数
     */
    public static long nowToTimestamp () {
        return dateToTimestamp(LocalDateTime.now());
    }
}
